1. /* sdflogxe.cpp by K.Tsuru */
  2. // function ID 3404 DRADIX Renewal since ver. 2.30
  3. /********************************************************************
  4. SDouble class
  5. It returns the natural logalithm log x for x > 0 using Exp(x).
  6. [Algorithm]
  7. It is well known that the convergence of logarithmic series is very slow. It costs
  8. much time in a normal method. Then we shall introduce the following idea.
  9. Pay attention to an identity
  10. x = exp(r){1-(1-x*exp(-r))}
  11. we obtain
  12. log(x) = r+log(1-x1)
  13. where x1= 1-x*exp(-r).
  14. The value of 'r' can be arbitrarily chosen because of identity.
  15. The solution of an equation x1=0 is r=log(x), then evaluating it by double
  16. the 'x1' has a very small value, order of 10^(-15).
  17. Further solving a equation (1+u)/(1-u)=1-x1 with respect to 'u' we obtain
  18. u = -x1/(2.0-x1);
  19. and
  20. log(1-x1) = log{(1+u)/(1-u)}= 2*(u + u^3/3 + u^5/5 +...).
  21. The square of 'u' has an order of 10^(-30) for any x(or r), then in order to
  22. obtain the value in 400 figures it is necessary to sum up only about 15 terms.
  23. In the practical program an intermediate step is inserted in which the approximate
  24. value of 'r' is evaluated in rather large figures.The processing speed depends
  25. on that of exponential function Exp(x).When the value of x is too large or too
  26. small to treat by double, the processing time of Log(10) is added if it has not
  27. been evaluated yet.In othe case it does not depend on the value of 'x'.
  28. *********************************************************************/
  29. #ifndef SN_H
  30. #include "sn.h"
  31. #endif
  32. static void LogApproX(const SDouble& x, SDouble& approX); //sub-function
  33. static const char* const func = "LogE";
  34. static const int appFig = 32;
  35. // static const SDouble ONE(1.0);
  36. SDouble LogE(const SDouble& x){
  37. SDouble X, add;
  38. // x = X*10^exp. log(x) = log(X)+exp*log(10), add = exp*log(10), 0< X < 1
  39. if( GetLogxCalcMethod(x, X, add) ) return X; // x= 1 or 10, X=0 or log(10)
  40. RealSize C;
  41. // step 1 :It gets an approximate value by use of double log(double).
  42. uint ef = x.EffFig();
  43. uint fig = min( (uint)appFig, ef );
  44. //If the value of 'fig' is increased with figures, the speed is almost the same.
  45. C.SetEffFig(fig);
  46. SDouble r;
  47. r.SetZero();
  48. LogApproX(X, r);
  49. C.SetEffFig(0);
  50. // step 2 :Using the approximate value of step 1 it gets in the full precision.
  51. if(ef > (uint)appFig) LogApproX(X, r);
  52. if(add.Sign(3401)) r += add;
  53. return r;
  54. }
  55. /*********************************************************
  56. Zero or approximate value is given to 'approX'.
  57. When approX=0 it takes as r=log(doubleD(x)). In other case
  58. r=approX.
  59. The value
  60. log(x) = r+log(1-x1)
  61. evaluated by series is overwritten on 'approX'.
  62. *********************************************************/
  63. static void LogApproX(const SDouble& x, SDouble& approX){
  64. SDouble x1, r, delta;
  65. delta = ONE - x;
  66. // x == 1.0 ?
  67. if( delta.Sign(3401) == 0 ){ // X == 1.0
  68. approX.SetZero(); return;
  69. }
  70. int fexp; //fixed exponent when r != 0, r = log(x)
  71. if(delta.RdxExp() < -appFig){
  72. //When x is very close to 1 (x==1 in double precision), xd = 1.0, r = 0.0 and x1 = 1.0 - x.
  73. //It includes the case in which 'doubleD' cannot be used.
  74. r.SetZero(); // r = 0
  75. x1 = delta; // delta = one - x;
  76. fexp = approX.Sign() ? approX.RdxExp() : x1.RdxExp();
  77. } else {
  78. RealSize C;
  79. uint upPrec = 0;
  80. if(approX.Sign(3401)) r = approX;
  81. else{
  82. r = log(doubleD(x)); //evaluated by double
  83. /*
  84. Because |x1| is very small it increases the effective figures to avoid
  85. the cancellation. This is necessary to exactly obtain the self-evident
  86. relation "log(e^1.25) = 1.25" by the following judgement "if(x1.IsMLT(r))".
  87. */
  88. upPrec = x.Hidden();
  89. upPrec = x.ProperUpPrec(upPrec);
  90. if(upPrec) C.SetEffFig(x.EffFig() + upPrec, C.TEMP_EXTEND);
  91. }
  92. //It evaluates by SDouble, the sign of 'x1' is unknown.
  93. x1 = ONE - x*Exp(-r);
  94. // |x1| is O(10^(-15))
  95. if(upPrec) C.SetEffFig(0);
  96. if(x1.IsMLT(r)){ // 'x1' is a value including error only.|x1|<<|r|
  97. approX = r; return; //A precision value has been obtained because
  98. //of the nice value of 'approX'.
  99. }
  100. fexp = r.RdxExp();
  101. if(x1.RdxExp() > -2) x.SetError(x.FATAL, func, 3401);
  102. }
  103. /*
  104. Evaluation log(1-x1) by series.
  105. It enters into the fixed point mode with a fixed exponent 'fexp'.
  106. Here the vlaue of 'x' is short or very small decimal fraction, then
  107. it does not provide the SDecimal function.
  108. See also "SinSeries" and "Asin".
  109. */
  110. // (1+u)/(1-u) = 1 - x1, x1 and u is very small.
  111. const SDouble u = x1/(x1 - 2.0), usq = u*u;
  112. r.FixedPoint(fexp);
  113. #if 1 // 5.85 (sec)
  114. SDouble v = u, sum = u; // sum = (1/2)log{(1+u)/(1-u)}= u + u^3/3 + u^5/5 +u^7/7+...
  115. v *= usq;
  116. sum += DsDiv(v, 3);
  117. ulong k = 5, mt = x.SlOpMaxValue();
  118. do{
  119. v *= usq;
  120. delta = DsDiv(v, k);
  121. sum += delta;
  122. if( (k += 2) > mt ){
  123. sum.SetError(sum.NOT_CONVERGE, func, 3401);
  124. break;
  125. }
  126. } while(delta.Sign(3401));
  127. r.PointFree();
  128. approX = DsMult(sum, 2); // includes Reform()
  129. #else // 5.87(sec)
  130. SDouble sum = ONE; // log{(1+u)/(1-u)}= 2u*(1 + u^2/3 + u^4/5 +u^6/7 +...)
  131. SDouble v = usq;
  132. sum += DsDiv(v, 3);
  133. ulong k = 5, mt = x.SlOpMaxValue();
  134. do{
  135. v *= usq;
  136. delta = DsDiv(v, k);
  137. sum += delta;
  138. if( (k += 2) > mt ){
  139. sum.SetError(sum.NOT_CONVERGE, func, 3401);
  140. break;
  141. }
  142. } while(delta.Sign(3401));
  143. r.PointFree();
  144. approX = u * DsMult(sum, 2); // includes Reform()
  145. //end of the calculation of 'log(1-x1)'
  146. #endif
  147. if(r.Sign(3401)) approX += r;
  148. x.upToTerm = (k-1)/2;
  149. return;
  150. }

sdflogxe.cpp : last modifiled at 2016/08/25 16:34:07(5,574 bytes)
created at 2017/10/07 10:22:50
The creation time of this html file is 2017/10/07 11:29:39 (Sat Oct 07 11:29:39 2017).